Skip to content

feat(ui): add request a demo modal#3766

Merged
waleedlatif1 merged 16 commits intostagingfrom
feat/demo-modal
Mar 25, 2026
Merged

feat(ui): add request a demo modal#3766
waleedlatif1 merged 16 commits intostagingfrom
feat/demo-modal

Conversation

@TheodoreSpeaks
Copy link
Collaborator

@TheodoreSpeaks TheodoreSpeaks commented Mar 25, 2026

Summary

Migrated over to sim native modal for requesting demos.
Added this modal to pricing and hero pages. I skipped the enterprise section in the top app bar and footer because we're going to have an enterprise page anyways.

  • Created demo-request-modal using EMCN components for use in pricing and hero sections of landing page
  • Created /demo-request endpoint to handle sending emails to enterprise@sim.ai

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation
  • Other: ___________

Testing

  • Tested with invalid inputs in hero and pricing sections
  • Tested with valid inputs in hero and pricing sections. Validated email send arguments are correct, but don't have email creds locally so didn't test emails landed in enterprise inbox.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

Screenshots/Videos

hero page screenshot
image

Success:
image

Error:
image

Enterprise "Get a demo" in pricing section
image

Success:
image

Error:
image

@vercel
Copy link

vercel bot commented Mar 25, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Mar 25, 2026 10:29pm

Request Review

@TheodoreSpeaks
Copy link
Collaborator Author

@cursor review

@cursor
Copy link

cursor bot commented Mar 25, 2026

PR Summary

Medium Risk
Adds a new public-facing form + API endpoint that sends email (with rate limiting) and changes email header handling to prevent injection; errors here could impact lead capture or outbound email delivery. Remaining changes are mostly SEO/docs metadata and UI polish, lower risk.

Overview
Adds a new “Request/Book a demo” flow: a DemoRequestModal with zod validation is wired into the landing Hero, Pricing, and Enterprise CTA, and a new POST /api/demo-requests endpoint validates input, rate-limits by IP, and sends a transactional email to enterprise@….

Hardens outbound email handling by adding email-header control character detection and subject sanitization in mailer.ts, reusing the same constraints in help/integration-request APIs; accompanying tests are updated/expanded.

Improves integrations SEO and rendering by switching metadata/canonicals to getBaseUrl(), adding integrations to sitemap.ts, using next/image in dropdowns/integration pages, and ensuring related-integrations CTA renders consistently.

Updates docs/data generation: expands HubSpot tool docs (deals/tickets/line items/quotes/appointments/carts/owners/marketing events/lists + pagination fields), tweaks Rippling paging wording, enriches many integration operation descriptions in integrations.json, improves generate-docs.ts tool-id mapping via switch/case parsing, and fixes Upstash tool-id selection mapping.

Written by Cursor Bugbot for commit 769a804. Configure here.

@TheodoreSpeaks TheodoreSpeaks marked this pull request as ready for review March 25, 2026 19:44
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 25, 2026

Greptile Summary

This PR replaces external Typeform links with a native DemoRequestModal component across the hero and pricing sections of the landing page, and introduces a new /api/demo-requests endpoint that sends an internal email notification to enterprise@sim.ai.

  • New DemoRequestModal — A fully controlled, client-rendered form with inline Zod validation (field-level errors, control-character guards on name fields, email format validation) and distinct success/error states. The modal is wired to both the hero page and the Enterprise pricing card.
  • New /api/demo-requests route — Rate-limited per IP (10 tokens, 5 refill/min), server-side Zod validation with demoRequestSchema, and sendEmail with the validated payload sent to the enterprise inbox.
  • Email header injection hardening — Addresses prior review feedback by adding NO_EMAIL_HEADER_CONTROL_CHARS_REGEX to firstName/lastName schema constraints and adding a prepareEmailHeaders function in mailer.ts that validates recipients/sender/reply-to for control characters and sanitizes subjects.
  • Accessibility and SEO improvements — Adds a skip-to-main-content link, removes userScalable: false from the global viewport, replaces decorative <h1> tags inside preview components with <p>, and adds integration pages to the sitemap.
  • blog-dropdown and docs-dropdown — Migrated from plain <img> to next/image with fill and explicit sizes props for better LCP optimization.

Confidence Score: 5/5

  • Safe to merge — all prior security concerns have been addressed and no new critical issues were found.
  • The PR is well-structured: the email header injection concern from prior review is fully resolved (both at the schema level and in prepareEmailHeaders), the useMemo nit and the resetForm/submitSuccess ordering concern are gone, client- and server-side validation are consistent, rate limiting is in place, and the new EMCN FormField component follows existing patterns. The only remaining comments are minor style suggestions (unused dep in useCallback, redundant role='presentation', and a silent default in the Upstash switch) that do not affect correctness or security.
  • No files require special attention.

Important Files Changed

Filename Overview
apps/sim/app/api/demo-requests/route.ts New POST endpoint to handle demo requests: rate-limited per IP, validates input with demoRequestSchema (including control-char guards on name fields), sanitizes the email subject at the mailer layer, and sends an internal notification to enterprise@sim.ai.
apps/sim/app/(home)/components/demo-request/demo-request-modal.tsx New client-side modal component for demo requests. Well-structured with inline Zod validation, clear success/error states, and proper aria attributes. Minor nit: resetForm is listed in handleSubmit's dependency array but never called inside it.
apps/sim/app/(home)/components/demo-request/consts.ts Defines the shared Zod schema, enums, and label-lookup helpers for demo requests. Correctly applies NO_EMAIL_HEADER_CONTROL_CHARS_REGEX on name fields and uses quickValidateEmail for the email field.
apps/sim/lib/messaging/email/mailer.ts Adds prepareEmailHeaders function that validates recipients, sender, and reply-to for control characters and sanitizes the subject by replacing CRLF sequences with spaces. Addresses the email header injection concern raised in prior review.
apps/sim/lib/messaging/email/utils.ts Exports EMAIL_HEADER_CONTROL_CHARS_REGEX, NO_EMAIL_HEADER_CONTROL_CHARS_REGEX, and hasEmailHeaderControlChars — reusable primitives for email header injection prevention used across the new endpoint and existing routes.
apps/sim/app/(home)/components/pricing/pricing.tsx Replaces external Typeform link with the native DemoRequestModal for the Enterprise tier CTA. Uses an action discriminator on the tier config and falls back to /signup when href is absent for non-demo tiers.
apps/sim/blocks/blocks/upstash.ts Converts the tool-ID selector from string interpolation to an explicit switch statement for clarity. The default case silently falls back to upstash_redis_get, which could mask future unhandled operations.
apps/sim/app/layout.tsx Removes maximumScale: 1 / userScalable: false from the viewport config (accessibility improvement) and removes the globally-injected structured data script (likely now emitted per-page instead).

Sequence Diagram

sequenceDiagram
    participant User
    participant DemoRequestModal
    participant API as /api/demo-requests
    participant Mailer as mailer.ts
    participant Email as Email Provider

    User->>DemoRequestModal: Click "Get a demo" / "Book a demo"
    DemoRequestModal->>DemoRequestModal: Client-side Zod validation (demoRequestSchema)
    alt Validation fails
        DemoRequestModal-->>User: Show inline field errors
    else Validation passes
        DemoRequestModal->>API: POST /api/demo-requests (JSON body)
        API->>API: IP rate-limit check (10 tokens/min)
        alt Rate limit exceeded
            API-->>DemoRequestModal: 429 Too Many Requests
            DemoRequestModal-->>User: Show error message
        else Within limit
            API->>API: Server-side Zod validation + control-char check
            API->>Mailer: sendEmail({ to: enterprise@sim.ai, replyTo: companyEmail })
            Mailer->>Mailer: prepareEmailHeaders() — validate recipients, sanitize subject
            Mailer->>Email: Send transactional email
            Email-->>Mailer: Success / Failure
            Mailer-->>API: { success: true }
            API-->>DemoRequestModal: 201 { success: true }
            DemoRequestModal-->>User: Show success screen
        end
    end
Loading

Reviews (3): Last reviewed commit: "fix(upstash): throw on unknown operation..." | Re-trigger Greptile

@TheodoreSpeaks
Copy link
Collaborator Author

@greptile review

Co-authored-by: Theodore Li <TheodoreSpeaks@users.noreply.github.com>
Co-authored-by: Theodore Li <TheodoreSpeaks@users.noreply.github.com>
Co-authored-by: Theodore Li <TheodoreSpeaks@users.noreply.github.com>
cursoragent and others added 2 commits March 25, 2026 20:31
Co-authored-by: Theodore Li <TheodoreSpeaks@users.noreply.github.com>
Co-authored-by: Theodore Li <TheodoreSpeaks@users.noreply.github.com>
- Fix endsWith over-matching: basename === 'index.ts'/'types.ts' instead
  of endsWith(), which was silently skipping valid tool files like
  list_leave_types.ts, delete_index.ts, etc.
- Add extractSwitchCaseToolMapping() to resolve op ID → tool ID mismatches
  where block switch statements map differently (e.g. HubSpot get_carts →
  hubspot_list_carts)
- Fix double fs.readFileSync in writeIntegrationsJson — reuse existing
  fileContent variable instead of re-reading the file
- Remove 5 dead functions superseded by *FromContent variants
- Simplify extractToolsAccessFromContent to use matchAll
- fix(upstash): replace template literal tool ID with explicit switch cases
@waleedlatif1
Copy link
Collaborator

@cursor review

@waleedlatif1
Copy link
Collaborator

@greptile

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

@waleedlatif1 waleedlatif1 merged commit be6b00d into staging Mar 25, 2026
6 checks passed
@waleedlatif1 waleedlatif1 deleted the feat/demo-modal branch March 25, 2026 22:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants